package me.yuzho.study.concurrency;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import net.mindview.util.*;
import static net.mindview.util.Print.*;

class ExchangerProducer<T> implements Runnable {

    private Generator<T> generator;
    private Exchanger<List<T>> exchanger;
    private List<T> holder;
    
    public ExchangerProducer(Exchanger<List<T>> exchanger, Generator<T> generator, List<T> holder) {
        this.exchanger = exchanger;
        this.generator = generator;
        this.holder = holder;
    }
    
    @Override
    public void run() {
        try {
            
            while (!Thread.interrupted()) {
                if(holder.size() > 0) {
                    print("Size of holder: " + holder.size());
                }
                
                for(int i=0; i<ExchangerDemo.size; i++){
                    holder.add(generator.next());
                }
                holder = exchanger.exchange(holder);
                //print("Exchange successfully in producer");
            }
            
        } catch (InterruptedException e) {
            print("Interrupted when exchanging in producer");
        }
        
        print("Produce completed!!!");
    }
    
}

class ExchangeConsumer<T> implements Runnable {
    
    private Exchanger<List<T>> exchanger;
    private List<T> holder;
    private volatile T value;
    
    ExchangeConsumer(Exchanger<List<T>> exchanger, List<T> holder) {
        this.exchanger = exchanger;
        this.holder = holder;
    }

    @Override
    public void run() {
        
        try {
            
            while (!Thread.interrupted()) {
                holder = exchanger.exchange(holder);
                //print("Exchange successfully in consumer");
                for(T x : holder){
                    value = x; // fetch out value
                    holder.remove(x); // OK for CopyOnWriteArrayList
                }
            }
            
        } catch (InterruptedException e) {
            print("Interrupted when exchanging in consumer");
        }
        
        print("Final value: " + value);
        
    }
    
}

public class ExchangerDemo {

    static int size = 10;
    static int delay = 5; // seconds
    
    public static void main(String[] args) throws InterruptedException {
        if(args.length > 0) {
            size = new Integer(args[0]);
        }
        
        if(args.length > 1) {
            delay = new Integer(args[1]);
        }
        
        ExecutorService exec = Executors.newCachedThreadPool();
        Exchanger<List<Fat>> xc = new Exchanger<List<Fat>>();
        
        List<Fat> producerList = new CopyOnWriteArrayList<Fat>(),
                consumerList = new CopyOnWriteArrayList<Fat>();
        
        exec.execute(new ExchangerProducer(xc, BasicGenerator.create(Fat.class), producerList));
        exec.execute(new ExchangeConsumer(xc, consumerList));
        
        TimeUnit.SECONDS.sleep(delay);
        exec.shutdownNow();
        
    }
    
}
